package com.hqd.ch03.v13.registry.support;

import com.hqd.ch03.v13.factory.ObjectFactory;
import com.hqd.ch03.v13.registry.SingletonBeanRegistry;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
    /**
     * 三级缓存，只有Bean存在循环依赖时触发，做特殊处理，其他Bean按照正常初始化流程
     */
    private final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>();
    /**
     * 二级缓存，保证三级缓存使用ObjectFactory创建出来的对象唯一
     */
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();

    /**
     * 一级缓存，存储初始化完的单例对象
     */
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();


    @Override
    public Object getSingleton(String beanName) {
        Object single = singletonObjects.get(beanName);
        if (single == null) {
            single = earlySingletonObjects.get(beanName);
            if (single == null) {
                ObjectFactory<?> objectFactory = this.singletonFactories.get(beanName);
                if (objectFactory != null) {
                    single = objectFactory.getObject();
                    this.earlySingletonObjects.put(beanName, single);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
        return single;
    }

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        /**
         * 只有bean未初始化完成才能加入三级缓存
         */
        if (!this.singletonObjects.containsKey(beanName)) {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
        }
    }

    protected void addSingleton(String beanName, Object obj) {
        this.singletonObjects.put(beanName, obj);
        this.earlySingletonObjects.remove(beanName);
        this.singletonFactories.remove(beanName);
    }

    @Override
    public boolean containsSingleton(String beanName) {
        return singletonObjects.containsKey(beanName);
    }

    @Override
    public void registerSingleton(String beanName, Object obj) {
        singletonObjects.put(beanName, obj);
    }
}
